package solver;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import model.IncrementalCostCalculator;
import model.IncrementalValidator;
import model.Problem;
import model.Process;
import model.Service;
import model.Solution;
import model.SolverEnvironment;

import command.IncrementalMoveProcessToMachineCommand;
import command.Invoker;

public class SelectionAgent3 {
	final int MAX_SAME_MACHINE_OCCURENCES = 5;
	final int MAX_MACHINES_PER_PROCESS = 20; // not used

	Map<Integer, Integer> frequencies;

	List<Integer> selectedProcesses;
	List<Integer> processList;
	List<Integer> machinesList;

	Invoker invoker;
	SolverEnvironment env;
	IncrementalValidator iv;
	IncrementalCostCalculator cc;
	Problem problem;
	Random random;
	Solution current_solution;

	public SelectionAgent3(SolverEnvironment env) {
		this.env = env;
		this.iv = env.getValidator();
		this.cc = env.getCostCalculator();
		this.problem = env.getProblem();
		this.random = env.getRandom();
		this.current_solution = env.getCurrentSolution();
		invoker = env.getInvoker();
		this.processList = new ArrayList<Integer>();
		this.machinesList = new ArrayList<Integer>();
		for (int p = 0; p < problem.P; p++) {
			processList.add(p);
		}
		for (int m = 0; m < problem.M; m++) {
			machinesList.add(m);
		}
	}

	public void setCurrentSolution(Solution sol) {
		env.setCurrentSolution(sol);
	}

	public List<Integer> getSelectedProcesses() {
		return selectedProcesses;
	}

	public void selectProcessesAndMachinesBucket() {
		System.out.println("selectProcessesAndMachinesBucket");
		int number_of_processes_per_machine = 4;
		int buckets = 12;
		int number_of_machines_per_bucket = 2;
		int[][] machines_per_bucket = new int[buckets][number_of_machines_per_bucket];
		reorderMachinesList();
		selectedProcesses = new ArrayList<Integer>();
		int k = 0;
		for (int i = 0; i < buckets; i++) {
			List<Integer> selected_processes_for_bucket = new ArrayList<Integer>();
			for (int j = 0; j < number_of_machines_per_bucket; j++) {
				int m = machinesList.get(k % problem.M);
				machines_per_bucket[i][j] = m;
				k++;
				List<Integer> processes = new ArrayList<Integer>();
				for (Integer p : env.getCurrentSolution()
						.getProcessesForMachine(m)) {
					processes.add(p);
				}
				int sm = processes.size() > number_of_processes_per_machine ? number_of_processes_per_machine
						: processes.size();
				Collections.shuffle(processes, random);
				for (int t = 0; t < sm; t++)
					selected_processes_for_bucket.add(processes.get(t));
			}
			for (Integer p : selected_processes_for_bucket) {
				Process aProcess = env.getProblem().getProcesses().get(p);

				// add current machine
				int process_current_machine = env.getCurrentSolution()
						.getMachineIdForProcessId(p);
				aProcess.addEligibleMachine(process_current_machine);

				// add initial machine
				int process_initial_machine = env.getInitialSolution()
						.getMachineIdForProcessId(p);
				if (process_initial_machine != process_current_machine)
					aProcess.addEligibleMachine(process_initial_machine);

				// add other machines
				for (int j = 0; j < number_of_machines_per_bucket; j++) {
					int m = machines_per_bucket[i][j];
					if (m != process_current_machine)
						if (isTransientFeasible(p, m))
							aProcess.addEligibleMachine(m);
				}
				if (aProcess.getEligibleMachines().size() > 1)
					selectedProcesses.add(p);
				else
					System.out.printf(
							"p%d REJECTED: only one eligible machine\n", p);
			}
		}
		cleanUpSelectedProcessesAndEligibleMachines();
		problem.printSelectedProcessesAndEligibleMachines(selectedProcesses, false, env);
	}

	int resource_counter = -1;

	private void reorderMachinesList() {
		if (random.nextDouble() <= 0.8)
			Collections.shuffle(machinesList, random);
		else {
			resource_counter++;
			// System.out.println("Order by resource " + resource_counter
			// % problem.RE);
			current_solution.refreshLoadCostContribution();
			int[] m_a = new int[problem.M];
			long[] cc = new long[problem.M];
			for (int i = 0; i < problem.M; i++) {
				m_a[i] = i;
				// cc[i] = current_solution.balance_cost_contribution_zipped[i]
				// + current_solution.load_cost_contribution_zipped[i];
				cc[i] = current_solution.load_cost_contribution_unzipped[i][resource_counter
						% problem.RE];
			}
			for (int i = 1; i < cc.length; i++) {
				for (int j = cc.length - 1; j >= i; j--) {
					if (cc[j - 1] > cc[j]) {
						long temp1 = cc[j];
						cc[j] = cc[j - 1];
						cc[j - 1] = temp1;
						int temp2 = m_a[j];
						m_a[j] = m_a[j - 1];
						m_a[j - 1] = temp2;
					}
				}
			}
			machinesList = new ArrayList<Integer>();
			for (int i = 0; i < problem.M; i++) {
				machinesList.add(m_a[i]);
			}
		}
	}

	private void reorderMachinesListOriginal() {
		Collections.shuffle(machinesList, random);
	}

	// Makes moves of type: p1m1 goes to m2
	public void selectProcessesAndMachinesBasedOnOneProcessMove(int nop,
			int noem) {
		System.out.println("selectProcessesAndMachinesBasedOnOneProcessMove");
		int[] counters = new int[problem.M];
		Set<Integer> distinctProcesses = new HashSet<Integer>();

		frequencies = new HashMap<Integer, Integer>();

		int LIMIT = 400;
		int[][] promising_moves = new int[LIMIT][3];
		int c = 0;
		Problem.VERBOSE = false;
		cc.computeCost();
		Collections.shuffle(processList, random);
		// System.out.println(processList);
		outer: for (Integer p1 : processList) {
			int m1 = current_solution.getMachineIdForProcessId(p1);
			reorderMachinesList();
			// System.out.println(machinesList);
			for (Integer m2 : machinesList) {
				if (counters[m2] > MAX_SAME_MACHINE_OCCURENCES)
					continue;
				if (iv.isProbablyFeasibleNoSchedule(p1, m1, m2)
						&& iv.isFinallyFeasibleNoSchedule(p1, m1, m2)) {
					long delta = cc.getProcessMoveToMachineCost(
							env.getCurrentSolution(), p1, m1, m2);
					if (delta < 0) {
						// System.out.printf("p%d m%d->m%d (%d)\n", p1,
						// m1, m2, -delta);
						if (machinesPerProcessMaxValueReached(p1))
							continue outer;
						promising_moves[c][0] = p1;
						promising_moves[c][1] = m2;
						promising_moves[c][2] = (int) (-delta);
						counters[m2]++;
						c++;
						if (c == LIMIT) {
							break outer;
						}
					}
				}
			}
		}

		sort(promising_moves, c);

		Set<Integer> distinctMachines = new HashSet<Integer>();
		selectedProcesses = new ArrayList<Integer>();
		int L = c < LIMIT / 2 ? c : LIMIT / 2;
		int max = 0;
		for (int i = 0; i < L; i++) {
			int p1 = promising_moves[i][0];
			int m2 = promising_moves[i][1];
			// System.out.printf("if p%d goes to m%d profit = %,d\n", p1, m2,
			// promising_moves[i][2]);
			if (promising_moves[i][2] > max)
				max = promising_moves[i][2];
			Process aProcess = problem.getProcesses().get(p1);
			if (!selectedProcesses.contains(p1)) {
				selectedProcesses.add(p1);
				aProcess.clearEligibleMachines();
				aProcess.addEligibleMachine(current_solution
						.getMachineIdForProcessId(p1));
			}
			aProcess.addEligibleMachine(m2);
			distinctProcesses.add(p1);
			if (distinctProcesses.size() > nop)
				break;
			distinctMachines.add(m2);
			if (distinctMachines.size() > 50)
				break;
		}
		System.out.printf("Minimum anticipated gain=%,d\n", max);
		problem.printSelectedProcessesAndEligibleMachines(selectedProcesses, false, env);
	}

	public boolean machinesPerProcessMaxValueReached(int p) {
		if (frequencies.containsKey(p)) {
			if (frequencies.get(p) == MAX_MACHINES_PER_PROCESS)
				return true;
			else
				frequencies.put(p, frequencies.get(p) + 1);
		} else {
			frequencies.put(p, 1);
		}
		return false;
	}

	// Makes moves of type: p1m1 goes to m2 p2m2 goes to m1
	public void selectProcessesAndMachinesBasedOnTwoProcessesExchangeMove(
			int nop, int noem) {
		System.out
				.println("selectProcessesAndMachinesBasedOnTwoProcessesExchangeMove");
		int[] counters = new int[problem.M];
		Set<Integer> distinctProcesses = new HashSet<Integer>();
		frequencies = new HashMap<Integer, Integer>();
		int LIMIT = 400;
		int[][] promising_moves = new int[LIMIT][3];
		int c = 0;
		int c2 = 0;
		Problem.VERBOSE = false;
		Collections.shuffle(processList, random);
		// System.out.println(processList);

		loopm1: for (Integer p1 : processList) {
			int m1 = current_solution.getMachineIdForProcessId(p1);
			reorderMachinesList();
			// System.out.println(machinesList);
			loopm2: for (Integer m2 : machinesList) {
				loopm3: for (Integer p2 : current_solution
						.getProcessesForMachine(m2)) {
					if (p1.equals(p2))
						continue;
					if (counters[m2] > MAX_SAME_MACHINE_OCCURENCES)
						continue loopm2;
					if (counters[m1] > MAX_SAME_MACHINE_OCCURENCES)
						continue loopm1;
					if (iv.isProcessExchangeFeasibleNoSchedule(p1, p2)) {
						long delta = cc.getProcessExcahngeProfit(
								current_solution, p1, p2);
						if (delta < 0) {
							// if (machinesPerProcessMaxValueReached(p1))
							// continue loopm1;
							// if (machinesPerProcessMaxValueReached(p2))
							// continue loopm3;
							promising_moves[c][0] = p1;
							promising_moves[c][1] = p2;
							promising_moves[c][2] = (int) (-delta);
							counters[m1]++;
							counters[m2]++;
							c++;
							if (c == LIMIT)
								break loopm1;
						}
					}
				}
			}
		}

		sort(promising_moves, c);

		selectedProcesses = new ArrayList<Integer>();
		int L = c < LIMIT / 2 ? c : LIMIT / 2;
		int max = 0;
		for (int i = 0; i < L; i++) {
			int p_id1 = promising_moves[i][0];
			int p_id2 = promising_moves[i][1];
			int m_id1 = current_solution.getMachineIdForProcessId(p_id1);
			int m_id2 = current_solution.getMachineIdForProcessId(p_id2);
			// System.out.printf("if p%dm%d exchanges with p%dm%d profit = %,d\n",
			// p_id1, m_id1, p_id2, m_id2, promising_moves[i][2]);
			if (promising_moves[i][2] > max)
				max = promising_moves[i][2];
			Process aProcess1 = problem.getProcesses().get(p_id1);
			if (!selectedProcesses.contains(p_id1)) {
				selectedProcesses.add(p_id1);
				aProcess1.clearEligibleMachines();
				aProcess1.addEligibleMachine(m_id1);
			}
			aProcess1.addEligibleMachine(m_id2);

			Process aProcess2 = problem.getProcesses().get(p_id2);
			if (!selectedProcesses.contains(p_id2)) {
				selectedProcesses.add(p_id2);
				aProcess2.clearEligibleMachines();
				aProcess2.addEligibleMachine(m_id2);
			}
			aProcess2.addEligibleMachine(m_id1);

			distinctProcesses.add(p_id1);
			distinctProcesses.add(p_id2);
			if (distinctProcesses.size() > nop)
				break;
		}
		System.out.printf("Minimum anticipated gain = %,d\n", max);
		problem.printSelectedProcessesAndEligibleMachines(selectedProcesses, false, env);
	}

	// Makes moves of type: p1m1 goes to m2 and p2m2 goes to m3
	public void selectProcessesAndMachinesBasedOnTwoProcessesAndThreeMachinesMove(
			int nop, int noem) {
		System.out
				.println("selectProcessesAndMachinesBasedOnTwoProcessesAndThreeMachinesMove");
		int[] counters = new int[problem.M];
		Set<Integer> distinctProcesses = new HashSet<Integer>();

		int LIMIT = 400;
		int[][] promising_moves = new int[LIMIT][4];
		int c = 0;
		int c2 = 0;
		List<Integer> machinesList2 = new ArrayList<Integer>();

		for (int m = 0; m < problem.M; m++) {
			machinesList2.add(m);
		}
		Problem.VERBOSE = false;

		Collections.shuffle(processList, random);
		// System.out.println(processList);
		long[] costComponentMemory = cc.getCostComponentMemory();
		outer: for (Integer p1 : processList) {
			int m1 = current_solution.getMachineIdForProcessId(p1);
			reorderMachinesList();
			// System.out.println(machinesList);
			loopm2: for (Integer m2 : machinesList) {
				if (m1 == m2.intValue())
					continue;
				Collections.shuffle(machinesList2);
				for (Integer p2 : current_solution.getProcessesForMachine(m2)) {
					if (p1.equals(p2))
						continue;
					cc.saveCostComponentsState();
					loopm3: for (Integer m3 : machinesList2) {
						if ((iv.isProbablyFeasibleNoSchedule(p2, m2, m3))
								&& (iv.isFinallyFeasibleNoSchedule(p2, m2, m3))) {
							c2++;
							if (c2 == LIMIT * 5) {
								invoker.undoAllCommands();
								break outer;
							}
							long delta = cc.getProcessMoveToMachineCost(
									current_solution, p2, m2, m3);
							IncrementalMoveProcessToMachineCommand cmd = new IncrementalMoveProcessToMachineCommand(
									iv, cc);
							cmd.setP_id(p2);
							cmd.setM_id(m3);
							invoker.addCommand(cmd);
							invoker.executeLastCommand();
							cc.updateNewSolutionCost();
							if ((iv.isProbablyFeasibleNoSchedule(p1, m1, m2))
									&& iv.isFinallyFeasibleNoSchedule(p1, m1,
											m2)) {
								delta += cc.getProcessMoveToMachineCost(
										current_solution, p1, m1, m2);
								if (delta < 0) {
									// System.out
									// .printf("p%dm%d->m%d, p%dm%d->m%d  (%d)\n",
									// p1, m1, m2, p2, m2,
									// m3, -delta);
									promising_moves[c][0] = p1;
									promising_moves[c][1] = p2;
									promising_moves[c][2] = m3;
									promising_moves[c][3] = (int) (-delta);
									counters[m2]++;
									counters[m3]++;
									c++;
									if (c == LIMIT) {
										invoker.undoAllCommands();
										break outer;
									}
									if (counters[m2] > MAX_SAME_MACHINE_OCCURENCES) {
										invoker.undoAllCommands();
										continue loopm2;
									}
									if (counters[m3] > MAX_SAME_MACHINE_OCCURENCES) {
										invoker.undoAllCommands();
										continue loopm3;
									}
								}
							}
						}
						invoker.undoAllCommands();
					}
				}
			}
		}
		invoker.undoAllCommands();
		cc.setAndRestoreCostComponentMemory(costComponentMemory);

		sort(promising_moves, c);

		selectedProcesses = new ArrayList<Integer>();
		int L = c < LIMIT / 2 ? c : LIMIT / 2;
		for (int i = 0; i < L; i++) {
			int p1 = promising_moves[i][0];
			int m1 = current_solution.getMachineIdForProcessId(p1);
			int p2 = promising_moves[i][1];
			int m2 = current_solution.getMachineIdForProcessId(p2);
			int m3 = promising_moves[i][2];
			// System.out.printf("if p%dm%d->%d and p%dm%d->%d profit = %,d\n",
			// p1, m1, m2, p2, m2, m3, promising_moves[i][3]);
			Process aProcess1 = problem.getProcesses().get(p1);
			if (!selectedProcesses.contains(p1)) {
				selectedProcesses.add(p1);
				aProcess1.clearEligibleMachines();
				aProcess1.addEligibleMachine(m1);
			}
			aProcess1.addEligibleMachine(m2);

			Process aProcess2 = problem.getProcesses().get(p2);
			if (!selectedProcesses.contains(p2)) {
				selectedProcesses.add(p2);
				aProcess2.clearEligibleMachines();
				aProcess2.addEligibleMachine(m2);
			}
			aProcess2.addEligibleMachine(m3);

			distinctProcesses.add(p1);
			distinctProcesses.add(p2);
			if (distinctProcesses.size() > nop)
				break;
		}
		augmentEligibleMachines(selectedProcesses, noem);
		boolean expandedPrint = true;
		problem.printSelectedProcessesAndEligibleMachines(selectedProcesses, expandedPrint, env);
	}

//	private void printSelectedProcessesAndEligibleMachines(boolean expanded) {
//		Set<Integer> machines = new HashSet<Integer>();
//		StringBuilder sb = new StringBuilder();
//		int xvars = 0;
//		for (Integer p : selectedProcesses) {
//			Process aProcess = problem.getProcesses().get(p);
//			xvars += aProcess.getEligibleMachines().size();
//			machines.addAll(aProcess.getEligibleMachines());
//		}
//		int i = 0;
//		for (Integer p : selectedProcesses) {
//			Process aProcess = problem.getProcesses().get(p);
//			i++;
//			if ((!expanded) && (i >= 5)) {
//				sb.append(String.format("and %d others...\n",
//						selectedProcesses.size() - i));
//				break;
//			} else {
//				Collections.sort(aProcess.getEligibleMachines());
//				int im = env.getCurrentSolution().getMachineIdForProcessId(p);
//				int cm = env.getInitialSolution().getMachineIdForProcessId(p);
//				sb.append(String.format("%d) p%d_im%d_cm%d --> %s\n", i, p, im,
//						cm, aProcess.getEligibleMachines()));
//			}
//		}
//
//		sb.append(String.format("XVARS=%d PROCESSES=%d MACHINES=%d\n", xvars,
//				selectedProcesses.size(), machines.size()));
//		System.out.println(sb.toString());
//	}

	private void augmentEligibleMachines(List<Integer> selectedProcesses,
			int noem) {
		// constructFixedProcessesList();
		// Set<Integer> machineUnion = new HashSet<Integer>();
		// for (Integer p : selectedProcesses) {
		// machineUnion.addAll(problem.getEligibleMachinesFor(p));
		// }
		// List<Integer> machines = new ArrayList<Integer>(machineUnion);
		// for (Integer p : selectedProcesses) {
		// Collections.shuffle(machines, random);
		// List<Integer> ep = problem.getEligibleMachinesFor(p);
		// int c = 0;
		// while (ep.size() < noem && c < machines.size()) {
		// int em = machines.get(c);
		// if (!ep.contains(em) && (isFeasibleMove(p, em)))
		// ep.add(machines.get(c));
		// c++;
		// }
		// }
	}

	// constructFixedProcessesList() must be called before consecutive
	// isFeasibleMove calls
	private boolean isFeasibleMove(List<Integer> fixed_processes, int p, int m) {
		Process aProcess = problem.getProcesses().get(p);
		Service aService = problem.getServices().get(aProcess.getService());

		// check conflict constraint
		List<Integer> aProcessList = current_solution.getProcessesForMachine(m);
		for (Integer p2 : aProcessList) {
			if ((fixed_processes.contains(p2))
					&& (problem.getServiceIdForProcessId(p2) == problem
							.getServiceIdForProcessId(p))) {
				System.out
						.printf("CONFLICT CONSTRAINT: p%d cannot be positioned in m%d\n",
								p, m);
				return false;
			}
		}
		// check dependency constraint
		int neighborhood_m = problem.getNeighborhoodIdForMachineId(m);
		for (Integer s : aService.getDependsOn()) {
			Set<Integer> presenceInNeighborhoods = new HashSet<Integer>();
			for (Integer p2 : problem.getProcessesIdsForServiceId(s)) {
				if (fixed_processes.contains(p2)) {
					int m2 = current_solution.getMachineIdForProcessId(p2);
					presenceInNeighborhoods.add(problem
							.getNeighborhoodIdForMachineId(m2));
				}
			}
			if (!presenceInNeighborhoods.contains(neighborhood_m)) {
				System.out
						.printf("DEPENDENCY CONSTRAINT: p%d cannot be positioned in m%d\n",
								p, m);
				return false;
			}
		}

		// check spread constraint
		// must be checked 2/2/2011
		int current_machine_id = current_solution.getMachineIdForProcessId(p);
		int current_location_of_process = problem
				.getLocationIdForMachineId(current_machine_id);
		int spread = current_solution.getSpreadForService(aService.getId());
		if (spread == aService.getSpreadMin()) {
			int c = 0;
			for (Integer p2 : aService.getProcesses()) {
				if (selectedProcesses.contains(p2))
					c++;
			}
			// check if p is the only process from service aService in
			// selectedProcesses
			if (c == 1) {
				// find locations of processes that are fixed from service
				// aService
				Set<Integer> presenceInLocationsForFixedProcesses = new HashSet<Integer>();
				for (Integer p2 : aService.getProcesses()) {
					if (p2 == p)
						continue;
					int m2 = current_solution.getMachineIdForProcessId(p2);
					presenceInLocationsForFixedProcesses.add(problem
							.getLocationIdForMachineId(m2));
				}
				if (presenceInLocationsForFixedProcesses
						.contains(current_location_of_process)) {
					System.out
							.printf("SPREAD CONSTRAINT: p%d cannot be positioned in m%d\n",
									p, m);
					return false;
				}
			}
		}
		return true;
	}

	private void sort(int[][] promising_moves, int M) {
		int N = promising_moves[0].length;
		for (int i = 1; i < M; i++) {
			for (int j = M - 1; j >= i; j--) {
				if (promising_moves[j - 1][N - 1] < promising_moves[j][N - 1]) {
					for (int k = 0; k < N; k++) {
						int temp = promising_moves[j - 1][k];
						promising_moves[j - 1][k] = promising_moves[j][k];
						promising_moves[j][k] = temp;
					}
				}
			}
		}
	}

	public void fillSelectedProcessesAndEligibleMachinesRandomly(int nop,
			int noem) {
		System.out.println("selectProcessesAndMachinesRandomly");
		nop = nop < problem.P ? nop : problem.P;
		noem = noem < problem.M ? noem : problem.M;

		for (Integer p : selectedProcesses) {
			Collections.shuffle(machinesList, random);
			Process aProcess = problem.getProcesses().get(p);
			loop1: for (Integer candidate_machine_id : machinesList) {
				if (isTransientFeasible(p, candidate_machine_id)) {
					aProcess.addEligibleMachine(candidate_machine_id);
					if (aProcess.getEligibleMachines().size() == noem - 1)
						break loop1;
				}
			}
		}

		Collections.shuffle(processList, random);
		int p_index = 0;
		while ((selectedProcesses.size() < nop) && (p_index < problem.P)) {
			int p_id = processList.get(p_index);
			if (!selectedProcesses.contains(p_id)) {
				Process proc = problem.getProcesses().get(p_id);
				int current_machine_id = current_solution
						.getMachineIdForProcessId(p_id);
				int initial_machine_id = env.getInitialSolution()
						.getMachineIdForProcessId(p_id);
				proc.addEligibleMachine(current_machine_id);
				proc.addEligibleMachine(initial_machine_id);
				Collections.shuffle(machinesList, random);

				for_loop: for (Integer candidate_machine_id : machinesList) {
					if (isTransientFeasible(p_id, candidate_machine_id)) {
						proc.addEligibleMachine(candidate_machine_id);
						if (proc.getEligibleMachines().size() == noem - 1)
							break for_loop;
					}
				}
				if (proc.getEligibleMachines().size() > 1) {
					selectedProcesses.add(p_id);
				}
			}
			p_index++;
		}

		System.out.printf("Selected Processes = %s\n", selectedProcesses);
		cleanUpSelectedProcessesAndEligibleMachines();
		problem.printSelectedProcessesAndEligibleMachines(selectedProcesses, false, env);
	}

	private void cleanUpSelectedProcessesAndEligibleMachines() {
		System.out.println("$$$$$$$$$ CLEAN UP $$$$$$$$$$$$$$$$$$$$");
		List<Integer> fixed_processes = new ArrayList<Integer>();
		for (int i = 0; i < problem.P; i++) {
			if (!selectedProcesses.contains(i))
				fixed_processes.add(i);
		}
		List<Integer> processes_to_be_removed = new ArrayList<Integer>();
		for (Integer p : selectedProcesses) {
			Process aProcess = problem.getProcesses().get(p);
			int cm = env.getCurrentSolution().getMachineIdForProcessId(p);
			List<Integer> machines_to_be_removed = new ArrayList<Integer>();
			for (Integer m : aProcess.getEligibleMachines()) {
				if ((m.intValue() != cm)
						&& (!isFeasibleMove(fixed_processes, p, m)))
					machines_to_be_removed.add(m);
			}
			aProcess.removeElligibleMachines(machines_to_be_removed);
			if (aProcess.getEligibleMachines().size() == 1) {
				processes_to_be_removed.add(p);
				System.out.printf("REJECTED MACHINE %d\n", p);
			}
		}
		selectedProcesses.removeAll(processes_to_be_removed);
	}

	public boolean isTransientFeasible(int p, int m) {
		if (env.getIllegalMachines(p).contains(m)) {
			// System.out.printf(
			// "TRANSIENT CONSTRAINT: p%d cannot be positioned in m%d\n",
			// p, m);
			return false;
		} else
			return true;
	}
}
